#!/usr/bin/env python3
"""
EchoKit Configuration Validator - EchoKit配置验证器
验证EchoKit服务器配置文件的完整性和有效性
"""

import os
import re
import logging
import requests
from typing import Dict, Any, List, Tuple, Optional
from pathlib import Path


class EchoKitConfigValidator:
    """EchoKit配置验证器"""
    
    def __init__(self, logger=None):
        self.logger = logger or logging.getLogger(__name__)
        self.validation_errors = []
        self.validation_warnings = []
    
    def validate_config_file(self, config_path: str) -> Tuple[bool, List[str], List[str]]:
        """验证配置文件"""
        self.validation_errors.clear()
        self.validation_warnings.clear()
        
        try:
            if not os.path.exists(config_path):
                self.validation_errors.append(f"Configuration file not found: {config_path}")
                return False, self.validation_errors, self.validation_warnings
            
            # 尝试解析TOML文件
            try:
                import toml
                with open(config_path, 'r', encoding='utf-8') as f:
                    config = toml.load(f)
            except ImportError:
                self.validation_errors.append("toml library not available. Install with: pip install toml")
                return False, self.validation_errors, self.validation_warnings
            except Exception as e:
                self.validation_errors.append(f"Failed to parse TOML file: {e}")
                return False, self.validation_errors, self.validation_warnings
            
            # 验证基本结构
            self._validate_basic_structure(config)
            
            # 验证ASR配置
            self._validate_asr_config(config.get('asr', {}))
            
            # 验证TTS配置
            self._validate_tts_config(config.get('tts', {}))
            
            # 验证LLM配置
            self._validate_llm_config(config.get('llm', {}))
            
            # 验证视觉配置（如果存在）
            if 'vision' in config:
                self._validate_vision_config(config['vision'])
            
            is_valid = len(self.validation_errors) == 0
            
            if is_valid:
                self.logger.info(f"Configuration validation passed: {config_path}")
            else:
                self.logger.error(f"Configuration validation failed: {config_path}")
                for error in self.validation_errors:
                    self.logger.error(f"  - {error}")
            
            return is_valid, self.validation_errors, self.validation_warnings
            
        except Exception as e:
            self.validation_errors.append(f"Unexpected error during validation: {e}")
            return False, self.validation_errors, self.validation_warnings
    
    def _validate_basic_structure(self, config: Dict[str, Any]):
        """验证基本配置结构"""
        # 检查必需的顶级配置
        required_sections = ['asr', 'tts', 'llm']
        for section in required_sections:
            if section not in config:
                self.validation_errors.append(f"Missing required section: [{section}]")
        
        # 检查服务器地址
        if 'addr' not in config:
            self.validation_errors.append("Missing server address configuration: addr")
        else:
            addr = config['addr']
            if not self._validate_address_format(addr):
                self.validation_errors.append(f"Invalid address format: {addr}")
    
    def _validate_asr_config(self, asr_config: Dict[str, Any]):
        """验证ASR配置"""
        if not asr_config:
            self.validation_errors.append("ASR configuration is empty")
            return
        
        # 检查API token
        if 'paraformer_token' not in asr_config:
            self.validation_errors.append("Missing ASR token: paraformer_token")
        else:
            token = asr_config['paraformer_token']
            if not self._validate_env_var_or_value(token):
                self.validation_warnings.append("ASR token appears to be empty or invalid")
    
    def _validate_tts_config(self, tts_config: Dict[str, Any]):
        """验证TTS配置"""
        if not tts_config:
            self.validation_errors.append("TTS configuration is empty")
            return
        
        # 检查平台
        if 'platform' not in tts_config:
            self.validation_errors.append("Missing TTS platform")
        
        # 检查token
        if 'token' not in tts_config:
            self.validation_errors.append("Missing TTS token")
        else:
            token = tts_config['token']
            if not self._validate_env_var_or_value(token):
                self.validation_warnings.append("TTS token appears to be empty or invalid")
        
        # 检查speaker
        if 'speaker' not in tts_config:
            self.validation_warnings.append("Missing TTS speaker configuration")
    
    def _validate_llm_config(self, llm_config: Dict[str, Any]):
        """验证LLM配置"""
        if not llm_config:
            self.validation_errors.append("LLM configuration is empty")
            return
        
        # 检查必需字段
        required_fields = ['llm_chat_url', 'api_key', 'model']
        for field in required_fields:
            if field not in llm_config:
                self.validation_errors.append(f"Missing LLM field: {field}")
        
        # 验证URL格式
        if 'llm_chat_url' in llm_config:
            url = llm_config['llm_chat_url']
            if not self._validate_url_format(url):
                self.validation_errors.append(f"Invalid LLM URL format: {url}")
        
        # 验证API密钥
        if 'api_key' in llm_config:
            api_key = llm_config['api_key']
            if not self._validate_env_var_or_value(api_key):
                self.validation_warnings.append("LLM API key appears to be empty or invalid")
        
        # 验证数值参数
        numeric_fields = {
            'history': (0, 100),
            'timeout': (1, 300),
            'max_tokens': (1, 8192)
        }
        
        for field, (min_val, max_val) in numeric_fields.items():
            if field in llm_config:
                value = llm_config[field]
                if not isinstance(value, (int, float)) or not (min_val <= value <= max_val):
                    self.validation_errors.append(f"Invalid {field} value: {value} (must be between {min_val} and {max_val})")
        
        # 验证布尔参数
        boolean_fields = ['stream']
        for field in boolean_fields:
            if field in llm_config:
                value = llm_config[field]
                if not isinstance(value, bool):
                    self.validation_errors.append(f"Invalid {field} value: {value} (must be boolean)")
        
        # 验证系统提示词
        if 'sys_prompts' in llm_config:
            self._validate_system_prompts(llm_config['sys_prompts'])
    
    def _validate_vision_config(self, vision_config: Dict[str, Any]):
        """验证视觉配置"""
        # 检查基本字段
        if 'enabled' in vision_config and not isinstance(vision_config['enabled'], bool):
            self.validation_errors.append("vision.enabled must be boolean")
        
        # 验证Coze配置
        coze_fields = ['coze_api_key', 'coze_bot_id']
        for field in coze_fields:
            if field in vision_config:
                value = vision_config[field]
                if not self._validate_env_var_or_value(value):
                    self.validation_warnings.append(f"Vision {field} appears to be empty or invalid")
        
        # 验证摄像头配置
        if 'camera' in vision_config:
            camera_config = vision_config['camera']
            
            if 'rtsp_url' in camera_config:
                rtsp_url = camera_config['rtsp_url']
                if not self._validate_rtsp_url(rtsp_url):
                    self.validation_errors.append(f"Invalid RTSP URL: {rtsp_url}")
            
            if 'http_stream_port' in camera_config:
                port = camera_config['http_stream_port']
                if not isinstance(port, int) or not (1 <= port <= 65535):
                    self.validation_errors.append(f"Invalid HTTP stream port: {port}")
            
            if 'default_resolution' in camera_config:
                resolution = camera_config['default_resolution']
                if not self._validate_resolution(resolution):
                    self.validation_errors.append(f"Invalid resolution format: {resolution}")
        
        # 验证处理配置
        if 'processing' in vision_config:
            processing_config = vision_config['processing']
            
            boolean_fields = ['batch_processing', 'gpu_acceleration', 'model_quantization', 'cache_results']
            for field in boolean_fields:
                if field in processing_config and not isinstance(processing_config[field], bool):
                    self.validation_errors.append(f"vision.processing.{field} must be boolean")
    
    def _validate_system_prompts(self, sys_prompts: List[Dict[str, Any]]):
        """验证系统提示词"""
        if not isinstance(sys_prompts, list):
            self.validation_errors.append("sys_prompts must be a list")
            return
        
        for i, prompt in enumerate(sys_prompts):
            if not isinstance(prompt, dict):
                self.validation_errors.append(f"sys_prompts[{i}] must be a dictionary")
                continue
            
            if 'role' not in prompt:
                self.validation_errors.append(f"sys_prompts[{i}] missing 'role' field")
            elif prompt['role'] not in ['system', 'user', 'assistant']:
                self.validation_errors.append(f"sys_prompts[{i}] invalid role: {prompt['role']}")
            
            if 'content' not in prompt:
                self.validation_errors.append(f"sys_prompts[{i}] missing 'content' field")
            elif not isinstance(prompt['content'], str) or not prompt['content'].strip():
                self.validation_errors.append(f"sys_prompts[{i}] content must be non-empty string")
    
    def _validate_address_format(self, addr: str) -> bool:
        """验证地址格式"""
        pattern = r'^[\w\.-]+:\d+$'
        return bool(re.match(pattern, addr))
    
    def _validate_url_format(self, url: str) -> bool:
        """验证URL格式"""
        pattern = r'^https?://[\w\.-]+(/.*)?$'
        return bool(re.match(pattern, url))
    
    def _validate_rtsp_url(self, url: str) -> bool:
        """验证RTSP URL格式"""
        pattern = r'^rtsp://[\w\.-]+:\d+/\w+$'
        return bool(re.match(pattern, url))
    
    def _validate_resolution(self, resolution: str) -> bool:
        """验证分辨率格式"""
        pattern = r'^\d+x\d+$'
        return bool(re.match(pattern, resolution))
    
    def _validate_env_var_or_value(self, value: str) -> bool:
        """验证环境变量或值"""
        if not value:
            return False
        
        # 如果是环境变量格式，检查环境变量是否存在
        if value.startswith('${') and value.endswith('}'):
            env_var = value[2:-1]
            return bool(os.getenv(env_var))
        
        # 如果是直接值，检查是否非空
        return bool(value.strip())
    
    def test_api_connectivity(self, config_path: str) -> Dict[str, bool]:
        """测试API连接性"""
        results = {
            'llm_api': False,
            'coze_api': False
        }
        
        try:
            import toml
            with open(config_path, 'r', encoding='utf-8') as f:
                config = toml.load(f)
            
            # 测试LLM API
            llm_config = config.get('llm', {})
            if 'llm_chat_url' in llm_config:
                try:
                    response = requests.get(llm_config['llm_chat_url'], timeout=5)
                    results['llm_api'] = response.status_code < 500
                except:
                    results['llm_api'] = False
            
            # 测试Coze API（如果配置了视觉功能）
            vision_config = config.get('vision', {})
            if vision_config.get('enabled') and 'coze_api_key' in vision_config:
                # 这里可以添加Coze API连接测试
                # 由于需要实际的API调用，暂时标记为True如果配置存在
                results['coze_api'] = bool(vision_config.get('coze_api_key'))
            
        except Exception as e:
            self.logger.error(f"Error testing API connectivity: {e}")
        
        return results


def test_config_validator():
    """测试配置验证器"""
    validator = EchoKitConfigValidator()
    
    # 测试现有配置文件
    config_files = [
        "config/vision_enhanced_server_config.toml",
        "config/optimized_server_config.toml",
        "config/fixed_server_config.toml"
    ]
    
    print("Testing EchoKit Configuration Validator:")
    print("=" * 60)
    
    for config_file in config_files:
        if os.path.exists(config_file):
            print(f"\nValidating: {config_file}")
            print("-" * 40)
            
            is_valid, errors, warnings = validator.validate_config_file(config_file)
            
            print(f"Status: {'VALID' if is_valid else 'INVALID'}")
            
            if errors:
                print("Errors:")
                for error in errors:
                    print(f"  ❌ {error}")
            
            if warnings:
                print("Warnings:")
                for warning in warnings:
                    print(f"  ⚠️  {warning}")
            
            if is_valid:
                print("✅ Configuration is valid")
            
            # 测试API连接性
            connectivity = validator.test_api_connectivity(config_file)
            print(f"API Connectivity: {connectivity}")
        else:
            print(f"❌ Configuration file not found: {config_file}")


if __name__ == '__main__':
    test_config_validator()